package org.msfj.common.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.msfj.admin.feign.DicIndexApi;
import org.msfj.common.annotation.Constants;
import org.msfj.common.base.BaseController;
import org.msfj.common.enums.CodeValueEnum;
import org.msfj.common.exception.BusinessException;
import org.msfj.common.feign.SubmailApi;
import org.msfj.common.model.CommonResult;
import org.msfj.common.model.EnumsResult;
import org.msfj.common.model.UeditorResult;
import org.msfj.common.submail.SubMailMessage;
import org.msfj.common.util.CacheUtil;
import org.msfj.common.util.ClassUtil;
import org.msfj.common.util.FileUtil;
import org.msfj.common.util.VerifyCodeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 后台用户登录controller
 * @Author: like
 * @Email: like@deyatong.com
 * @Date: 2017-05-27 13:33:24
 * @Version: 1.0
 * @Created in idea by autoCode
 */
@Api(value = "后台通用接口", tags = "后台通用接口")
@RestController
public class CommonController extends BaseController {

    @Autowired
    private DicIndexApi dicIndexApi;

    @Value("${uploadPath}")
    private String uploadPath;

    @Value("${feignClient.name}")
    private String name;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private SubmailApi submailApi;

    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 获取验证码图片
     *
     * @return CommonResult.ok()
     */
    @RequestMapping("/getVerifyCode")
    @ApiOperation(value = "获取验证码图片", notes = "获取验证码图片")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "request", name = "request", dataType = "javax.servlet.http.HttpServletRequest", paramType = "path"),
            @ApiImplicitParam(value = "response", name = "response", dataType = "javax.servlet.http.HttpServletResponse", paramType = "path"),
    })
    public void getVerifyCode(HttpServletResponse response, String random) throws IOException {
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");

        //生成随机字串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        if (verifyCode.startsWith("0")) { // 存入 redis 后取出时 0开头会被 jackson 解析时报错不允许0开头的数字
            verifyCode = "9" + verifyCode.substring(1);
        }
        redisTemplate.opsForValue().set(random, verifyCode);
        redisTemplate.expire(random, 300, TimeUnit.SECONDS);
        //生成图片
        int w = 200, h = 80;
        VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode);
    }

    /**
     * 获取短信验证码
     *
     * @return
     */
    @RequestMapping("/getPhoneVerifyCode")
    @ApiOperation(value = "获取短信验证码", notes = "获取短信验证码")
    @ApiImplicitParam(value = "phone", name = "phone", dataType = "java.lang.String", paramType = "path")
    public CommonResult getPhoneVerifyCode(String phone, String random) {
        //生成随机字串
        String verifyCode = RandomUtil.randomNumbers(6);
        SubMailMessage subMailMessageVo = new SubMailMessage();
        Map<String, String> vars = CollectionUtil.newHashMap();
        if (verifyCode.startsWith("0")) { // 存入 redis 后取出时 0开头会被 jackson 解析时报错不允许0开头的数字
            verifyCode = "9" + verifyCode.substring(1);
        }
        vars.put("code", verifyCode);
        subMailMessageVo.setTo(phone);
        subMailMessageVo.setVars(vars);
        List<SubMailMessage> messageList = new ArrayList<>();
        messageList.add(subMailMessageVo);
        CommonResult<Boolean> b = this.submailApi.sendCommonPhoneValid(subMailMessageVo);
        if (b.isOK()) {
            verifyCode = b.getData() ? verifyCode : null;
            if (verifyCode != null) {
                redisTemplate.opsForValue().set(random, verifyCode);
                redisTemplate.expire(random, 300, TimeUnit.SECONDS);
                return CommonResult.ok();
            }
        }
        return CommonResult.error("短信发送失败，请重新获取");
    }

    /**
     * 验证图片验证码
     *
     * @param verifyCode
     * @return CommonResult.ok()
     */
    @RequestMapping("/validateVerifyCode")
    @ApiOperation(value = "验证验证码", notes = "验证验证码")
    @ApiImplicitParam(value = "verifyCode", name = "verifyCode", dataType = "java.lang.String", paramType = "path")
    public CommonResult validateVerifyCode(String verifyCode, String random) {
        if (validateVerifyCode(redisTemplate, verifyCode, random, false)) {
            return CommonResult.ok(true);
        }
        return CommonResult.build(200, "验证码不正确", false);
    }

    /**
     * 类型,状态,各个枚举类型的javascript对象
     */
    @RequestMapping(value = {"/enumsjs"}, produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取系统后台所有的枚举类型", notes = "获取系统后台所有的枚举类型")
    public String enumJS() {
        return "ENUMS = " + JSONUtil.toJsonStr(enums().getData());
    }

    /**
     * 类型,状态,各个枚举类型的javascript对象
     */
    @RequestMapping(value = {"/enums"}, produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取系统后台所有的枚举类型", notes = "获取系统后台所有的枚举类型")
    public CommonResult enums() {
        EnumsResult[] result = null;
        try {
            Object object = CacheUtil.getCache().get(Constants.ENUMS_CACHE_KEY);
            if (object != null) {
                result = (EnumsResult[]) object;
                return CommonResult.ok(result);
            } else {
                List<Class> allClassByInterface = ClassUtil.getAllClassByInterface(CodeValueEnum.class, "org.msfj.common.enums");
                List<Class> allZwfwClassByInterface = ClassUtil.getAllClassByInterface(CodeValueEnum.class, "org.msfj.zwfw.enums");
                allClassByInterface.addAll(allZwfwClassByInterface);
                if (CollectionUtil.isNotEmpty(allClassByInterface)) {
                    result = new EnumsResult[allClassByInterface.size()];
                    for (int i = 0; i < allClassByInterface.size(); i++) {
                        Class<? extends CodeValueEnum> anEnum = allClassByInterface.get(i);
                        EnumsResult enumsResult = new EnumsResult();
                        List<Map<String, Object>> value = CollectionUtil.newArrayList();
                        CodeValueEnum[] enumConstants = anEnum.getEnumConstants();
                        for (CodeValueEnum enumConstant : enumConstants) {
                            Map<String, Object> map = CollectionUtil.newHashMap();
                            map.put("code", enumConstant.getCode());
                            map.put("value", enumConstant.getValue());
                            map.put("var", enumConstant.toString());
                            value.add(map);
                        }
                        enumsResult.setName(anEnum.getSimpleName());
                        enumsResult.setValue(value);
                        result[i] = enumsResult;
                    }
                }
                CacheUtil.getCache().set(Constants.ENUMS_CACHE_KEY, result);
            }
        } catch (Exception e) {
            ExceptionUtil.getMessage(e);
        }
        return CommonResult.ok(result);
    }

    /**
     * 类型,状态,各个枚举类型的javascript对象
     */
    @RequestMapping(value = {"/dictsjs"}, produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取系统后台所有的字典数据", notes = "获取系统后台所有的字典数据")
    public String dicstJS() {
        return "DICTS = " + JSONUtil.toJsonStr(dicts().getData());
    }

    /**
     * 类型,状态,各个枚举类型的javascript对象
     */
    @RequestMapping(value = {"/dicts"}, produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取后台所有数据字典项目", notes = "获取后台所有数据字典项目")
    public CommonResult dicts() {
        return dicIndexApi.getAllDict();
    }

    /**
     * 上传文件
     *
     * @param uploadFile
     * @return UeditorResult
     */
    @RequestMapping("/upload")
    @ApiOperation(value = "上传文件", notes = "上传文件")
    @ApiImplicitParam(value = "uploadFile", name = "uploadFile", dataType = "org.springframework.web.multipart.MultipartFile", paramType = "path")
    public UeditorResult uploadFile(MultipartFile uploadFile){
        UeditorResult result = new UeditorResult();
        //判断图片是否为空
        if (uploadFile.isEmpty()) {
            result.setState("ERROR");
            logger.error("上传的文件是空文件");
            return result;
        }
        try {
            String originalFilename = uploadFile.getOriginalFilename();
            int index = originalFilename.lastIndexOf(".");
            //获取文件扩展名
            String ext_Name = "";
            if (index != -1) {
                ext_Name = originalFilename.substring(index, originalFilename.length());
            }else{
                result.setState("ERROR");
                logger.error("文件类型无法识别");
                return result;
            }
            String fileName = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT) + RandomUtil.randomNumbers(4) + ext_Name;
            //调用文件处理类FileUtil，处理文件，将文件写入指定位置
            FileUtil.uploadFile(uploadFile.getBytes(), uploadPath, fileName);
            String url = "/upload/" + fileName;
            if (StrUtil.isNotBlank(url)) {
                //转存文件
                result.setState("SUCCESS");
                result.setOriginal(originalFilename);
                result.setTitle(originalFilename);
                result.setUrl(url);
            } else {
                result.setState("ERROR");
                logger.error("上传失败");
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传文件失败", e);
            throw new BusinessException("上传失败");
        }
        return result;
    }
}
